package com.bto.solar.work.service;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import com.bto.solar.work.common.BizException;
import com.bto.solar.work.common.R;
import com.bto.solar.work.config.ConfigParams;
import com.bto.solar.work.constant.BizStageEnum;
import com.bto.solar.work.constant.BizTaskEnum;
import com.bto.solar.work.constant.Constants;
import com.bto.solar.work.dao.IDesignService;
import com.bto.solar.work.dao.IDeviceOptionService;
import com.bto.solar.work.dao.IDeviceService;
import com.bto.solar.work.dao.IOrderBaseService;
import com.bto.solar.work.dto.CheckDeviceValidRes;
import com.bto.solar.work.dto.order.DesignDto;
import com.bto.solar.work.dto.sto.OrderDeviceUsedReq;
import com.bto.solar.work.entity.Design;
import com.bto.solar.work.entity.Device;
import com.bto.solar.work.entity.OrderBase;
import com.bto.solar.work.entity.StoDevice;
import com.bto.solar.work.service.biz_stage_handler.ShiGongStageHandler;
import com.bto.solar.work.utils.BeanUtils;
import com.bto.solar.work.utils.NullUtils;
import com.bto.solar.work.utils.ServletUtils;
import com.bto.solar.work.utils.StringUtils;
import com.bto.solar.work.vo.DeviceVo;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author 王小波
 * @description:
 * @date 2023/9/26 14:20
 */
@Slf4j
@Service
public class BtoDeviceService {
    @Autowired
    private ConfigParams configParams;


    @Autowired
    private IDeviceOptionService deviceOptionService;
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private IDesignService designService;
    @Autowired
    @Lazy
    private ShiGongStageHandler shiGongStageHandler;
    @Autowired
    private BtoStoService btoStoService;
    @Autowired
    private BtoDesignService btoDesignService;
    @Autowired
    private IOrderBaseService orderBaseService;
    /**
     * 设计更新了设备信息
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateDesignDeviceInfo(String orderId) {
        List<Design> recentlyDesign = btoDesignService.getRecentlyDesign(orderId);
        if (NullUtils.isNotEmpty(recentlyDesign) && recentlyDesign.size() == 1) {
            return;
        }
        Design currentDesign = recentlyDesign.get(0);
        Design preDesign = recentlyDesign.get(1);


        List<DesignDto.DesignDevice> preDesignDevices = preDesign.getDesignDevice();
        List<DesignDto.DesignDevice> currentDesignDevices = currentDesign.getDesignDevice();

        List<String> dbDesignKeys = new ArrayList<>();
        List<String> updateDesignKeys = new ArrayList<>();

        preDesignDevices.forEach(dbDesign -> {
            String key = dbDesign.getDeviceType() + ":" + dbDesign.getDeviceSpec() + ":" + dbDesign.getQuantity();
            dbDesignKeys.add(key);
        });
        currentDesignDevices.forEach(updateDesign -> {
            String key = updateDesign.getDeviceType() + ":" + updateDesign.getDeviceSpec() + ":" + updateDesign.getQuantity();
            updateDesignKeys.add(key);
        });

        List<String> updateDeviceKeyList = updateDesignKeys.stream().filter(updateKey -> !dbDesignKeys.contains(updateKey)).collect(Collectors.toList());
        if (!updateDeviceKeyList.isEmpty()) {
            updateDeviceKeyList.forEach(key -> {
                //更新设备信息为待填写
                String taskId = BizTaskEnum.TASK_SBXX.getTaskId() + "_" + key.split(":")[0];
                shiGongStageHandler.updateToWaitingFilledState(orderId, BizStageEnum.CONSTRUCT.getStageId(), taskId);
            });
        }

    }

    /**
     * 检查上传的设备编码是否是有效的
     */
    public CheckDeviceValidRes checkUploadDeviceCodeIsValid(List<Device> uploadDeviceCodes) {
        List<String> codeList = uploadDeviceCodes.stream().map(Device::getDeviceNumber).collect(Collectors.toList());
        CheckDeviceValidRes res = new CheckDeviceValidRes();

        List<StoDevice> stoDeviceByCodes = btoStoService.getStoDeviceByCodes(codeList);
        List<String> stoDevicesIds = stoDeviceByCodes.stream().map(StoDevice::getDeviceId).collect(Collectors.toList());

        List<DeviceVo> validDevices = new ArrayList<>();
        List<Device> inExistenceDevices = new ArrayList<>();
        List<Device> specErrorDevices = new ArrayList<>();

        if (NullUtils.isEmpty(stoDeviceByCodes)) {
            uploadDeviceCodes.forEach(device -> {
                DeviceVo deviceVo = new DeviceVo();
                BeanUtils.copyPropertiesIgnoreNullValue(device, deviceVo);
                deviceVo.setValid("无效的设备编码");
                validDevices.add(deviceVo);
            });

            return res.setDeviceVos(validDevices);
        }

        //将sto中的设备信息复制过来
        uploadDeviceCodes.forEach(device -> {
            DeviceVo deviceVo = new DeviceVo();
            BeanUtils.copyPropertiesIgnoreNullValue(device, deviceVo);
            //没有匹配到的设备
            if (!stoDevicesIds.contains(device.getDeviceNumber())) {
                deviceVo.setValid("无效的设备编码");
                validDevices.add(deviceVo);
            }
            //匹配到的设备
            else {
                stoDeviceByCodes.forEach(stoDevice -> {
                    //找到对应的设备
                    if (device.getDeviceNumber().equals(stoDevice.getDeviceId())) {
                        List<DesignDto.DesignDevice> orderDesignDeviceSpecInfo = btoDesignService.getOrderDesignDeviceSpecInfo(device.getOrderId(), device.getDeviceType());
                        //没有规格要求
                        if (NullUtils.isEmpty(orderDesignDeviceSpecInfo)) {
                            validDevices.add(deviceVo);
                        }
                        //通过仓库设备表中的规格包含对应数值。就认为规格是匹配的
                        else if (stoDevice.getDeviceType().equals(device.getDeviceType()) &&
                                orderDesignDeviceSpecInfo.stream().anyMatch(designDevice -> {
                                    return StringUtils.isEmpty(designDevice.getDeviceSpec()) || stoDevice.getSpecs().contains(designDevice.getDeviceSpec());
                                })) {
                            validDevices.add(deviceVo);
                        }
                        //规格不匹配，设备码有效
                        else {
                            deviceVo.setValid("设备规格与设计不符");
                            validDevices.add(deviceVo);
                        }
                        device.setManufacturer(stoDevice.getManufacturer());
                        device.setModulePower(stoDevice.getModulePower());
                        device.setManufacturerNumber(stoDevice.getManufacturerNumber());
                        device.setSpecificationsModel(stoDevice.getSpecificationsModel());
                        device.setManufacturerShortCode(stoDevice.getManufacturerShortCode());
                        device.setManufacturerShortName(stoDevice.getManufacturerShortName());
                        deviceService.updateById(device);

                        deviceVo.setManufacturer(stoDevice.getManufacturer());
                        deviceVo.setModulePower(stoDevice.getModulePower());
                        deviceVo.setManufacturerNumber(stoDevice.getManufacturerNumber());
                        deviceVo.setSpecificationsModel(stoDevice.getSpecificationsModel());
                        deviceVo.setManufacturerShortCode(stoDevice.getManufacturerShortCode());
                        deviceVo.setManufacturerShortName(stoDevice.getManufacturerShortName());
                    }
                });
            }
            ;
        });
        res.setDeviceVos(validDevices);
        res.setInExistenceDevices(inExistenceDevices);
        res.setSpecErrorDevices(specErrorDevices);
        return res;
    }


    /**
     * 判断施工组件数量是否与设计一致
     */
    public boolean checkConstructDeviceZuJianCountEqualDesign(String orderId) {
        val device = deviceService.lambdaQuery()
                .eq(Device::getOrderId, orderId)
                .eq(Device::getDeviceType, Constants.DEVICE_TYPE_ZUJIAN).list();

        List<DesignDto.DesignDevice> orderDesignDeviceSpecInfo = btoDesignService.getOrderDesignDeviceSpecInfo(orderId, Constants.DEVICE_TYPE_ZUJIAN);
        AtomicReference<Integer> designDeviceCount = new AtomicReference<>(0);
        orderDesignDeviceSpecInfo.forEach(designDevice -> {
            designDeviceCount.updateAndGet(v -> v + designDevice.getQuantity());
        });

        CheckDeviceValidRes checkDeviceValidRes = checkUploadDeviceCodeIsValid(device);
        List<DeviceVo> collect = checkDeviceValidRes.getDeviceVos().stream().filter(deviceVo ->
                StringUtils.isEmpty(deviceVo.getValid())).collect(Collectors.toList());

        if (designDeviceCount.get().equals(collect.size())) {
            return true;
        }
        return false;
    }


    /**
    * 更新仓库设备已经被订单使用
    */
    public void updateOrderDevicesUsedInSto(String orderId){
        OrderBase orderBase = orderBaseService.getById(orderId);
        List<Device> devices = deviceService.lambdaQuery()
                .select(Device::getDeviceNumber)
                .in(Device::getDeviceType , Constants.NEED_VALID_CODE_DEV)
                .eq(Device::getOrderId, orderId).list();
        if(NullUtils.isAnyNull(orderBase , devices)){
            throw new BizException("订单 {} 施工资方审核通过，未找到订单/设备信息,同步STO" , orderId);
        }
        btoStoService.updateStoDevicesStoIdToOrderId(devices.stream().map(Device::getDeviceNumber).collect(Collectors.toList()), orderId);

        OrderDeviceUsedReq usedReq = new OrderDeviceUsedReq();
        usedReq.setOrderId(orderId);
        usedReq.setUsedDeviceIds(devices.stream().map(Device::getDeviceNumber).collect(Collectors.toList()));
        usedReq.setInstallationAddress(orderBase.getInstallationAddress());
        String deviceOrderUsedUrl = configParams.stoProxyUrl+"/sto/sto-device/device-ids-used-by-order";

        try {
            String authorization = ServletUtils.getHeader(ServletUtils.getRequest(), "Authorization");
            HttpRequest request = HttpRequest.post(deviceOrderUsedUrl)
                    .header("Authorization" , authorization)
                    .body(JSON.toJSONString(usedReq));
            HttpResponse response = request.execute();
            R r = JSON.parseObject(response.body(), R.class);
            if(!r.isSuccess()){
                log.error("订单 {}，同步STO失败");
            }
        }
        catch (Exception e){
            log.error("订单 {}，同步STO失败" , orderId , e.getMessage());
        }

    }
}
